import Redis from 'ioredis';


class DistributedLock {
    private redis: Redis;
    constructor( redis: Redis) {
        // 创建 Redis 连接实例
        this.redis = redis;
    }
    /**
     * 尝试获取锁
     * @param resourceKey 资源键名
     * @param uniqueValue 唯一值，用于标识锁的所有者
     * @param expireTime 锁的过期时间（秒）
     * @returns 是否成功获取锁
     */
    async acquireLock(resourceKey:string, uniqueValue:string, expireTime = 10) {
        const lockKey = `lock:${resourceKey}`;

        // Lua脚本用于原子获取锁
        const luaScript = `
      if redis.call('SET', KEYS[1], ARGV[1], 'NX', 'EX', ARGV[2]) then
        return 1
      else
        return 0
      end
    `;

        // 执行Lua脚本
        const result = await this.redis.eval(luaScript, 1, lockKey, uniqueValue, expireTime);

        if (result === 1) {
            console.log(`[s] Acquired lock for ${resourceKey}`);
            return true;
        } else {
            console.log(`[x] Failed to acquire lock for ${resourceKey}`);
            return false;
        }
    }
    /**
     * 释放锁
     * @param resourceKey 资源键名
     * @param value 唯一值，用于验证锁的所有者
     * @returns 是否成功释放锁
     */
    async releaseLock(resourceKey:string, value:string) {
        const lockKey = `lock:${resourceKey}`;

        // Lua脚本用于原子释放锁
        const luaScript = `
      if redis.call('GET', KEYS[1]) == ARGV[1] then
        return redis.call('DEL', KEYS[1])
      else
        return 0
      end
    `;

        // 执行Lua脚本
        const result = await this.redis.eval(luaScript, 1, lockKey, value);

        if (result === 1) {
            console.log(`[s] Released lock for ${resourceKey}`);
            return true;
        } else {
            console.log(`[x] Failed to release lock for ${resourceKey}. Lock may be owned by another process.`);
            return false;
        }
    }
}

// 示例用法
async function exampleUsage() {
    const redisConfig = {
        host: '127.0.0.1',
        port: 6379,
    };
    const redis = new Redis(redisConfig);
    const lockManager = new DistributedLock(redis);

    const resourceKey = 'exampleResource';
    const uniqueValue = 'uniqueValue';

    // 尝试获取锁
    const isLockAcquired = await lockManager.acquireLock(resourceKey, uniqueValue);

    if (isLockAcquired) {
        try {
            // 在这里执行受锁保护的代码

            // 模拟一些处理时间
            await new Promise(resolve => setTimeout(resolve, 5000));

        } finally {
            // 最后释放锁
            await lockManager.releaseLock(resourceKey, uniqueValue);
        }
    } else {
        console.log('[x] Lock not acquired. Another process may be holding the lock.');
    }

}

// 运行示例
(async () => {
    await Promise.all([ exampleUsage(), exampleUsage()]);
    await new Promise(resolve => setTimeout(resolve, 6000));
    await exampleUsage();

})()